#ifndef __PARSE_NODES_H__
#define __PARSE_NODES_H__

#include "ParseBaseNodes.h"
#define ACCEPT_FUNCTION void Accept(NodeVisitor*);

/* OUR NODES */
struct ClassDeclarationNode;
struct RootNode : ParentNode {
	ACCEPT_FUNCTION
	std::map<std::string, std::set<ClassDeclarationNode*, compare_decls> > class_environment;
};
struct IfStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct BinaryOperatorExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();

	std::string operation;
};

/* NODES DEFINED BY THE CFG */
struct CompilationUnitNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct PackageDeclarationNode : DeclarationNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ImportDeclarationsNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ImportDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct SingleTypeImportDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct TypeImportOnDemandDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct TypeDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};

struct InterfaceDeclarationNode;
struct ClassDeclarationNode : TypedNode, EnvironmentNode {
	ACCEPT_FUNCTION
	//Default constructor
	ClassDeclarationNode() : super(0x0) {}

	ParentNode* Convert(ParentNode*);
	std::string Type();

	std::string package_name;
	std::set<InterfaceDeclarationNode*> interfaces;
	ClassDeclarationNode *super;

};
struct ModifiersNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ModifierNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct SuperNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfacesNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfaceTypeListNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ClassBodyNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ClassBodyDeclarationsNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ClassBodyDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ClassMemberDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct FieldDeclarationNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct VariableDeclaratorNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct VariableInitializerNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct MethodDeclarationNode : TypedNode, EnvironmentNode {
	MethodDeclarationNode() : number_of_parameters(0) {}

	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();

	unsigned int number_of_parameters;
};
struct MethodHeaderNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct MethodDeclaratorNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct FormalParameterListNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct FormalParameterNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
	int Offset() { return index * 4 + 8; }
	
};
struct MethodBodyNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ConstructorDeclarationNode : MethodDeclarationNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ConstructorDeclaratorNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ConstructorBodyNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfaceDeclarationNode : ClassDeclarationNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ExtendsInterfacesNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfaceBodyNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfaceMemberDeclarationsNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfaceMemberDeclarationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct AbstractMethodDeclarationNode : MethodDeclarationNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct BlockNode : ParentNode, EnvironmentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct BlockStatementsNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct BlockStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct LocalVariableDeclarationStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct LocalVariableDeclarationNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
	int Offset() { return index * -4; }
};
struct StatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct StatementNoShortIfNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct StatementWithoutTrailingSubstatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct EmptyStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ExpressionStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct StatementExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct IfThenStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct IfThenElseStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct IfThenElseStatementNoShortIfNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct WhileStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct WhileStatementNoShortIfNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ForStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ForStatementNoShortIfNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ForInitNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ForUpdateNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ReturnStatementNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct PrimaryNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct PrimaryNoNewArrayNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};

struct ClassInstanceCreationExpressionWithoutArgumentsNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ArgumentListNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ArrayCreationExpressionNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct DimExprNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct FieldAccessNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();

	FieldDeclarationNode *field;
};
struct MethodInvocationWithoutArgumentsNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ArrayAccessNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
	TypeMeta array_type;
};
struct ExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct AssignmentNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct LeftHandSideNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ConditionalOrExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ConditionalAndExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InclusiveOrExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ExclusiveOrExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct AndExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct EqualityExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct RelationalExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct AdditiveExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct MultiplicativeExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct UnaryExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct UnaryExpressionNotPlusMinusNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct PostfixExpressionNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct CastExpressionNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ClassTypeNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct InterfaceTypeNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct TypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();


	bool isArray;
};
struct PrimitiveTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct NumericTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct IntegralTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ReferenceTypeNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ClassOrInterfaceTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ArrayTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct PrimitiveArrayTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct ObjectArrayTypeNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct NameNode : ParentNode {
	ACCEPT_FUNCTION
	NameNode() : declaration_reference(0x0), declaration_position(0), declaration_is_static_context(false) {}
	ParentNode* Convert(ParentNode*);
	std::string Type();

	std::vector<TypedNode*> visited_locations;

	unsigned int declaration_position;
	DeclarationNode::Namespace declaration_namespace;
	TypedNode *declaration_reference;
	bool declaration_is_static_context;
};

struct MethodInvocationNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();

	std::string method_identifier;
	MethodDeclarationNode *method;
};
struct ClassInstanceCreationExpressionNode : TypedNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();

	ConstructorDeclarationNode *constructor;
};
struct SimpleNameNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct QualifiedNameNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct LiteralNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};
struct IntegerLiteralNode : ParentNode {
	ACCEPT_FUNCTION
	IntegerLiteralNode() : ParentNode(), underlying_type(TypeMeta::Int) {}
	ParentNode* Convert(ParentNode*);
	std::string Type();
	bool IsParent();

	TypeMeta::TypeCategory underlying_type;
	long long value;
};
struct BooleanLiteralNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
	bool IsParent();

	bool value;
};
struct CharacterLiteralNode : IntegerLiteralNode {
	ACCEPT_FUNCTION

	ParentNode* Convert(ParentNode*);
	std::string Type();
	bool IsParent();
};
struct StringLiteralNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
	bool IsParent();

	std::string value;
};
struct NullLiteralNode : ParentNode {
	ACCEPT_FUNCTION
	ParentNode* Convert(ParentNode*);
	std::string Type();
};

struct TypeMetaReference : TypeMeta {
	TypeMetaReference() : TypeMeta(), integer_literal(0x0) {}
	TypeMetaReference(TypeMeta::TypeCategory t, ClassDeclarationNode *c, ParentNode *l) : TypeMeta(t, c), integer_literal((IntegerLiteralNode*)l) {}

	//We don't need to do any casting. Excellent
	union {
		IntegerLiteralNode *integer_literal;
		CharacterLiteralNode *character_literal;
		BooleanLiteralNode *boolean_literal;
		StringLiteralNode *string_literal;
		NullLiteralNode *null_literal;
	};
};
#endif